package marker.code;

import freemarker.template.Configuration;
import freemarker.template.Template;
import marker.fun.*;
import marker.xml.XmlParser;
import marker.xml.metadata.*;
import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.*;

public class CodeMarker {
	
	private final static XmlParser xmlParser = new XmlParser();

	public static Map<String, InfoBean> infoBeanMap = new HashMap<String, InfoBean>();
	
	public static List<Map> requestMap=new LinkedList<Map>();
	
	public static List<Map> responseMap=new LinkedList<Map>();

	public static Map<Integer, MsgBean> msgBean1 = new TreeMap<Integer, MsgBean>();
	
	public static Map<Integer, MsgBean> msgBean2 = new TreeMap<Integer, MsgBean>();
	
	public static List<Map<String,Object>> configs=new LinkedList<Map<String,Object>>();
	
	private Configuration cfg=createConfiguration();
	
	public void createCode(String path) throws Exception {
		initXml(path);
		createInfoBean();
		createMsgBean();
		createFile();
		createOneFileCode("server",Constants.MsgPackage , "MessageCode.java", "JavaMessageCode.html");
		createOneFileCode("server",Constants.HandlerPackage , "handler.properties", "HandlerProperties.html");
		createOneFileCode("client",Constants.MsgPackage , "MessageCode.as", "AsMessageCode.html");
		createOneFileCode("client",Constants.MsgPackage , "ResponseBeanParse.as", "AsResponseBeanParse.html");
		
		//客户端发的消息端口号，可用于功能开关控制
//		createMsgCodeFile();
	}

	private void createOneFileCode(String srcDir,String packages,String fileName,String templeteName) {
		String projectDir=System.getProperty("user.dir")+"/"+Constants.CodePath;
		Map config=new HashMap();
		config.put("reqs", requestMap);
		config.put("resps", responseMap);
		Template temp=newTemplate(templeteName);
		//生板生成文件
		OutputStreamWriter os=null;
		try {
			//文件目录
			String filePath=FilePathUtils.parsePackageToPath(packages,projectDir,srcDir);
			// 指定模板
			os=new OutputStreamWriter(new FileOutputStream(new File(filePath+fileName)),"utf-8");
			temp.process(config, os);
		}catch (Exception e) {
			e.printStackTrace();
		}finally{
			if(os!=null){
				try {
					os.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	private Template newTemplate(String name){
		Template temp =null;
		try {
			temp= cfg.getTemplate(name);
		} catch (IOException e1) {
			e1.printStackTrace();
		}
		return temp;
	}

	private void createFile() {
		createOneMsgTemplete("server",".java","JaveBean.html");
		createHanlderTempete("server", ".java", "JavaHandler.html");
		createOneMsgTemplete("client", ".as", "AsBean.html");
	}
	
	private Configuration createConfiguration(){
		cfg=new Configuration();
		cfg.setDefaultEncoding("UTF-8");
		// 指定模板所在的classpath目录
		cfg.setClassForTemplateLoading(this.getClass(), "/templet");
		// 添加一个"宏"共享变量用来将属性名字母大写
		cfg.setSharedVariable("UC", new UpperCharacter());
		//首字母大
		cfg.setSharedVariable("UFC", new UpperFirstCharacter());
		cfg.setSharedVariable("TYPE", new TypeStr());
//		cfg.setSharedVariable("CTYPE", new CShapeType());
		cfg.setSharedVariable("ATYPE", new AsType());
		cfg.setSharedVariable("LTYPE", new LayaType());
		cfg.setSharedVariable("DEFVAL", new TypeDefaultVal());
		return cfg;
	}

	private void createOneMsgTemplete(String scrDir,String fileExtName,String templeteName){
		String projectDir=System.getProperty("user.dir")+"/"+Constants.CodePath;
		Template temp =newTemplate(templeteName);
		for(Map<String,Object> config:configs){
			//生板生成文件
			OutputStreamWriter os=null;
			try {
				//处理包结构
				String packageStr=(String)config.get("package");
				//文件目录
				String filePath=FilePathUtils.parsePackageToPath(packageStr,projectDir,scrDir);
				String name=(String)config.get("name");
				filePath+=name+fileExtName;
				// 指定模板
				os=new OutputStreamWriter(new FileOutputStream(new File(filePath)),"utf-8");
				temp.process(config, os);
			}catch (Exception e) {
				e.printStackTrace();
			}finally{
				if(os!=null){
					try {
						os.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		}
	}
	
	private void createHanlderTempete(String scrDir,String fileExtName,String templeteName){
		String projectDir=System.getProperty("user.dir")+"/"+Constants.CodePath;
		// 指定模板
		Template temp =null;
		try {
			temp= cfg.getTemplate(templeteName);
		} catch (IOException e1) {
			e1.printStackTrace();
		}
		for(MsgBean msgBean : msgBean1.values()){
			Map config=convertMsgConfigToHandConfig(msgBean);
			if(msgBean.isRequest()){
				requestMap.add(config);
				//生板生成文件
				OutputStreamWriter os=null;
				try {
					//文件目录
					String filePath=FilePathUtils.parsePackageToPath(Constants.HandlerPackage+"."+config.get("module"),projectDir,scrDir);
					String name=(String)config.get("name")+"Handler";
					filePath+=name+fileExtName;
					os=new OutputStreamWriter(new FileOutputStream(new File(filePath)),"utf-8");
					temp.process(config,os);
				}catch (Exception e) {
					e.printStackTrace();
				}finally{
					if(os!=null){
						try {
							os.close();
						} catch (IOException e) {
							e.printStackTrace();
						}
					}
				}
			}else{
				responseMap.add(config);
			}
		}
	}
	
	private Map convertMsgConfigToHandConfig(MsgBean config){
		Map newmap=new HashMap();
		newmap.put("module", config.getModule());
		newmap.put("name", config.getName());
		newmap.put("author", Constants.author);
		newmap.put("desc", config.getDesc());
		newmap.put("type", config.isRequest()?"REQUEST":"RESPONSE");
		newmap.put("code", String.valueOf(config.getCode()));
		newmap.put("consName", config.getConstName());
		return newmap;
	}
	/**消息bean对象*/
	private void createInfoBean() throws IOException {
		Collection<InfoBean> infoBeans = infoBeanMap.values();
		for (InfoBean infoBean : infoBeans) {
			Map<String,Object> config=new HashMap<String,Object>();
			Set<String> imports = new HashSet<String>();
			Set<Map> properties=new LinkedHashSet<Map>();
			for (Property property : infoBean.getAllProperties()) {
				properties.add(getPropertyConfig(property,imports));
			}
			config.put("imports", imports);
			config.put("module", infoBean.getModule());
			config.put("desc", infoBean.getDesc());
			config.put("name", infoBean.getSimpleClassName());
			config.put("properties", properties);
			config.put("oldName", infoBean.getName());
			config.put("package", infoBean.getPackage());
			config.put("type", "BEAN");
			config.put("author",Constants.author);
			this.configs.add(config);
		}

	}
	/**构建消息对象**/
	private void createMsgBean() throws IOException {
		Collection<MsgBean> msgBeans = msgBean2.values();
		for (MsgBean msgBean : msgBeans) {
			Map<String,Object> config=new HashMap<String,Object>();
			Set<String> imports = new HashSet<String>();
			Set<Map> properties=new LinkedHashSet<Map>();
			AbstractBean bean = null;
			if (msgBean.isRequest()) {
				bean = new RequestBean(msgBean);
			} else {
				bean = new ResponseBean(msgBean);
			}
			for (Property property : bean.getAllProperties()) {
				properties.add(getPropertyConfig(property,imports));
			}
			config.put("imports", imports);
			config.put("module", msgBean.getModule());
			config.put("desc", msgBean.getDesc());
			config.put("name", bean.getSimpleClassName());
			config.put("oldName", msgBean.getName());
			config.put("properties", properties);
			config.put("package", bean.getPackage());
			if(msgBean.isRequest()){
				config.put("type", "REQ");
				config.put("respDesc", msgBean.getReturnMsg());
			}else{
				config.put("type", "RESP");
			}
			config.put("conName", msgBean.getConstName());
			config.put("author", Constants.author);
			this.configs.add(config);
		}
	}
	/**构建属性列表*/
	private Map<String,Object> getPropertyConfig(Property property,Set<String> imports){
		Map<String,Object> pro=new HashMap<String,Object>();
		if (property.getRefType() !=null) {
			InfoBean refBean = infoBeanMap.get(property.getType());
			if (refBean != null) {
				imports.add(refBean.getClassName());
				pro.put("type", property.getType()+"Bean");
			}
		}
		pro.put("name", property.getName());
		pro.put("ref", property.getRefType()==null?"":property.getRefType());
		if(pro.get("type")==null){
			pro.put("type", property.getType());
		}
		pro.put("desc", property.getDesc());
		pro.put("isif", property.isInIf());
		List<IfInfo> ifInfos=property.getIfConditions();
		List<Map<String,Object>> ifList=new LinkedList<Map<String,Object>>();
		if(ifInfos!=null&&ifInfos.size()>0){
			for(IfInfo info:ifInfos){
				Map<String,Object> ifmap=new HashMap<String, Object>();
				ifmap.put("flag", getOperatorString(info.getOperation()));
				ifmap.put("value", info.getValue());
				List<Map> ifProperties=new LinkedList<Map>();
				for(Property p:info.getProperties()){
					Map<String,Object> ifPro=new HashMap<String,Object>();
//					if (property.getRefType() !=null) {
					if (p.getRefType() !=null) {
						InfoBean refBean = infoBeanMap.get(p.getType());
						if (refBean != null) {
							ifPro.put("type", p.getType()+"Bean");
						}
					}
					ifPro.put("name", p.getName());
					ifPro.put("ref", p.getRefType()==null?"":p.getRefType());
					if(ifPro.get("type")==null){
						ifPro.put("type", p.getType());
					}
					ifPro.put("desc", p.getDesc());
					ifPro.put("isif", p.isInIf());
					ifPro.put("ifs", new LinkedList());
					ifProperties.add(ifPro);
				}
				ifmap.put("properties", ifProperties);
				ifList.add(ifmap);
			}
		}
		pro.put("ifs", ifList);
		return pro;
	}
	
	private String getOperatorString(String operation) {
		if (operation.equals("等于")) {
			return "==";
		}
		if (operation.equals("大于等于")) {
			return ">=";
		}
		if (operation.equals("小于等于")) {
			return "<=";
		}
		if (operation.equals("大于")) {
			return ">";
		}
		if (operation.equals("小于")) {
			return "<";
		}
		if(operation.equals("不等于")){
			return "!=";
		}
		return operation;
	}
	
	private void initXml(String path) throws Exception {
	    	initInfoBean();
			initMsgBean(msgBean1);
			if(path!=null&&!path.equals("")){
				String msgBeanPath = Constants.RootPath + File.separatorChar + path;
				initMsgBean(msgBean2);
			}else{
				msgBean2=msgBean1;
			}
		 
	}

	private void initMsgBean(Map<Integer, MsgBean> msgBean) throws Exception {
		File file = new File(Constants.MsgPath);
		Collection<File> files = FileUtils.listFiles(file, new String[] { "xml" }, true);
		if (files != null && files.size() > 0) {
			for (File file2 : files) {
				MsgBean infoBean = null;
				try {
					infoBean = xmlParser.parseMsgBean(file2);
				} catch (Exception e) {
					throw new Exception("解析文件:" + file2 + "出错" + e.getMessage(), e);
				}
				msgBean.put(infoBean.getCode(), infoBean);
			}
		}
	}

	private void initInfoBean() throws Exception {
		File file = new File(Constants.BeanPath);
		Collection<File> files = FileUtils.listFiles(file, new String[] { "xml" }, true);
		if (files != null && files.size() > 0) {
			for (File file2 : files) {
				InfoBean infoBean = xmlParser.parseInfoBean(file2);
				infoBeanMap.put(infoBean.getName(), infoBean);
			}
		}
	}
}
